/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.taglibs.input;

import com.codemagi.util.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.*;
import org.apache.log4j.*;

/**
 *  This class implements the &lt;input:multiselect&gt; tag, which presents a
 *  &lt;SELECT MULTIPLE&gt; form element.
 *
 *  @version 1.0
 *  @author August Detlefsen for CodeMagi, Inc.
 */
public class MultiSelect extends Input {

    //set to true to view debug output
    Logger log = Logger.getLogger(this.getClass());

    private List dVec = new ArrayList();
    private OrderedTable options;       // what are our options? :)

    public void setDefault(String x) {
        dVec.add(x);
    }

    public void setDefault(Integer x) {
        if (x != null) dVec.add(x.toString());
    }

    public void setDefault(List x) {
        if (x != null) dVec = x;
    }

    public void setDefault(Set x) {
	log.debug(" setDefault( (Set)" + x + " )");
        if (x != null) {
	    dVec = new ArrayList();
	    dVec.addAll(x);
	}
    }

    public void setOptions(OrderedTable x) {
        options = x;
    }

    public int doStartTag() throws JspException {
        try {
            // sanity check
            if (name == null || name.equals(""))
                throw new JspTagException("invalid null or empty 'name'");

            // get what we need from the page
            ServletRequest req = pageContext.getRequest();
            JspWriter out      = pageContext.getOut();

            // start building up the tag
            out.println();
            out.println("<select multiple=\"multiple\" ");
            out.println("    name=\"" + Util.quote(name) + "\"");
            if (!Utils.isEmpty(id)) {
                out.println("    id=\"" + Util.quote(id) + "\"");
            }

	    //disable the form field if disabled is set                                                     
            if (disabled) {
                out.println("    readonly=\"readonly\"");
                out.println("    OnFocus=\"blur();\"");
		appendAttribute("style", "cursor:default;");
            }

            // include any attributes we've got here
            Util.printAttributes(out, attributes);

	    //if this is a required field and it is not filled out, do something...
	    if ( !Utils.isEmpty((String)req.getAttribute("error_" + name + "_error")) ) {
                out.println("    class=\"cminput_error\"");
            }

            // end the starting tag
            out.println(">");

            /*
             * Print out our options, selecting one or more if appropriate.
             */

            // get the current selection
            String[] selected = getParameterValues(name, (HttpServletRequest)req);
            log.debug("Select: selected: " + selected);
            log.debug("Select: (selected != null) = " + (selected != null));
            log.debug("Select: (selected != null && selected.length > 1) = " + (selected != null && selected.length > 1));
            log.debug("Select: (attributes == null) + " + (attributes == null));

            // load up the selected values into a hash table for faster access
            // otherwise use defaults
            HashMap chosen = new HashMap();

	    if (selected == null || override) {
                log.debug("Select: building chosen from default");

                Iterator e = dVec.iterator();

                while (e.hasNext()) {
		    Object dObj = e.next();
                    String dString = "";
		    if (dObj instanceof String) {
			dString = (String)dObj;
		    } else if (dObj != null) {
			dString = dObj.toString();
		    }
		    
                    log.debug("Select: chosen: " + dString);

                    chosen.put(dString, null);
                }
	    } else {
                log.debug("Select: building chosen from request");

                for (int i = 0; i < selected.length; i++) {
                    chosen.put(selected[i], null);
                }

            }

	    //previous if statement for above. note that action order was reversed
	    //           if (selected != null && !override ) {

            // actually print the <option> tags
            if (options != null) {
                Collection c = (Collection)(options.orderedKeys());
                Iterator i = c.iterator();

                while (i.hasNext()) {

		    String key;
		    String value;
		    
		    try {
			key   = (String)i.next();
			if (key == null) continue;  //do not allow null keys
			value = (String)options.get(key);
		    } catch (ClassCastException cce) {
			/* If the option contains non-Strings, give the user
			 * a more meaningful message than what he or she would get
			 * if we just propagated a ClassCastException back.
			 */
			throw new JspTagException("all members in options Map must be Strings");
		    }

                    if (value == null) value = key;   // use key if value is null

		    out.print("<option value=\"" + Util.quote(key) + "\"");

                    /*
                     * This may look confusing: we match the VALUE of
                     * this option pair with the KEY of the 'chosen' Map
                     * (We want to match <option>s on values, not keys.)
                     */
                    if ( chosen.containsKey(key) ) out.print(" selected=\"selected\"");

                    out.print(">");
                    out.print(Util.quote(value));
                    out.println("</option>");
                }
	    }

            // close off the surrounding select
            out.println("</select>");

            //show the error message
            if (showError) {
                String errorMessage = (String)req.getAttribute(name + "_error_message");
                if (errorMessage != null && !"".equals(errorMessage) ) {
                    out.print( "<BR><SPAN CLASS=\"input_error_msg\">" + errorMessage + "</SPAN>");
                }
            }

        } catch (Exception ex) {
	    log.debug("", ex);

            throw new JspTagException(ex.getMessage());
        }
        return SKIP_BODY;
    }
}


